import tkinter as tk

import numpy as np
import cv2
from PIL import Image, ImageTk


class ImageCanvas(tk.Canvas):
    def __init__(self, root, *args, **kwargs):
        super().__init__(root, *args, **kwargs)
        self.nothing = np.ones((800, 800, 3), dtype=np.uint8)  # 创建纯黑图片
        pil_img = Image.fromarray(self.nothing)
        self.nothing = ImageTk.PhotoImage(pil_img)
        self.is_nothing: bool = False
        self.show_nothing()  # 初始状态显示纯黑图片

    def show_image(self, imgBGR: np.ndarray):
        """在画布里居中显示图片"""
        try:
            self.tk_img, start_x, start_y = self._process_img(imgBGR)
            self.create_image((start_x, start_y), image=self.tk_img, anchor=tk.NW)
            self.is_nothing = False
        except Exception:
            self.show_nothing()

    def show_nothing(self):
        if not self.is_nothing:
            self.create_image((0, 0), image=self.nothing, anchor=tk.NW)
        self.is_nothing = True

    def _process_img(self, imgBGR: np.ndarray) -> tuple[ImageTk.PhotoImage, int, int]:
        """按比例缩放图片以适应画布"""
        # 调整颜色顺序
        image = cv2.cvtColor(imgBGR, cv2.COLOR_BGR2RGB)
        # 获取当前画布宽高
        max_w, max_h = self.winfo_width(), self.winfo_height()
        # 根据图片宽高计算图片宽高比例
        img_h, img_w, _ = image.shape
        img_ratio = img_w / img_h
        # 根据画布的最大尺寸计算缩放后的大小
        new_w = int(max_h * img_ratio)
        if new_w > max_w:
            new_h = int(max_w / img_ratio)
            w, h = max_w, new_h
        else:
            w, h = new_w, max_h
        # 计算图片在画布中的初始放置位置(居中)
        start_x = (max_w - w) // 2
        start_y = (max_h - h) // 2
        # 使用PIL中的resize函数重新缩放图片大小
        pil_img = Image.fromarray(image)
        pil_img = pil_img.resize((w, h))
        # 创建并返回可显示的tk图片对象
        return ImageTk.PhotoImage(pil_img), start_x, start_y
